package com.sojson.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sojson.base.impl.BaseUser;
import com.sojson.config.exception.TransErrorCode;
import com.sojson.config.exception.TransException;
import com.sojson.constant.Constant;
import com.sojson.constant.Lock;
import com.sojson.dao.MemberDao;
import com.sojson.dao.RoleDao;
import com.sojson.entity.bo.AuthcUser;
import com.sojson.entity.bo.Select;
import com.sojson.entity.po.BalanceLog;
import com.sojson.entity.po.Member;
import com.sojson.entity.vo.MemberVo;
import com.sojson.enums.EBalanceCount;
import com.sojson.enums.EBalanceTotalType;
import com.sojson.enums.EBalanceType;
import com.sojson.enums.core.EDisableAtType;
import com.sojson.enums.core.EGeneralYesNo;
import com.sojson.enums.core.EUserStatus;
import com.sojson.service.BalanceLogService;
import com.sojson.service.MemberService;
import com.sojson.util.DateUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.file.FileDepotUtil;
import com.sojson.util.file.constant.ConstantFileFieldName;
import com.sojson.util.file.enums.EFileTable;
import com.sojson.util.pwd.PwdUtil;
import com.sojson.util.token.Token;
import com.sojson.util.token.TokenUtil;
import com.sojson.util.token.TokenVo;
import com.sojson.util.verifycode.VerifyCodeUtil;
import com.sojson.util.verifycode.VerifyCodeUtil.Verify;

/**
 * 用户表Service实现类
 * 
 * @author liu
 * @date 2021-03-16
 */
@Service
public class MemberServiceImpl implements MemberService {

    @Autowired
    private MemberServiceImpl memberServiceImpl;
    @Autowired
    private BalanceLogService balanceLogService;
    @Resource
    private MemberDao memberDaoImpl;
    @Resource
    private RoleDao roleDaoImpl;

    /**
     * 单条插入
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int insert(Member member) {
        int insert = memberDaoImpl.insert(member);
        return insert;
    }

    /**
     * 批量插入
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int insertList(Member member) {
        int insertList = memberDaoImpl.insertList(member.getMembers());
        return insertList;
    }

    /**
     * 通过对象批量删除(物理删除)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByDto(Member member) {
        int deleteByDto = memberDaoImpl.deleteByDto(member);
        return deleteByDto;
    }

    /**
     * 统计全部数量
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public int countAll() {
        int countAll = memberDaoImpl.countAll();
        return countAll;
    }

    /**
     * 查询所有
     * 
     * @return
     * @throws SQLException
     */
    @Override
    public List<Member> findAll() {
        List<Member> findAll = memberDaoImpl.listAll();
        return findAll;
    }

    /**
     * 根据对象统计数量
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int countByDto(Member member) {
        int countByDto = memberDaoImpl.countByDto(member);
        return countByDto;
    }

    /**
     * 根据对象查询
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public List<Member> findByDto(Member member) {
        List<Member> findByDto = memberDaoImpl.listByDto(member);
        return findByDto;
    }

    /**
     * 通过id删除(物理删除)
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteById(Integer id) {
        int deleteById = memberDaoImpl.deleteById(id);
        return deleteById;
    }

    /**
     * 通过id列表删除(物理删除)
     * 
     * @param ids
     * @return
     * @throws SQLException
     */
    @Override
    public int deleteByIdList(ArrayList<Integer> ids) {
        int deleteByIdList = memberDaoImpl.deleteByIdList(ids);
        return deleteByIdList;
    }

    /**
     * 通过id更新(全部更新)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updateById(Member member) {
        int updateById = memberDaoImpl.updateById(member);
        return updateById;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容相同)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updateStaticByIdList(Member member) {
        int updateStaticByIdList = memberDaoImpl.updateStaticByIdList(member);
        return updateStaticByIdList;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容不相同)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updateChangeByIdList(Member member) {
        int updateChangeByIdList = memberDaoImpl.updateChangeByIdList(member.getMembers());
        return updateChangeByIdList;
    }

    /**
     * 通过id更新(局部更新)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updatePartialById(Member member) {
        Member findById = null;
        int updatePartialById = 0;
        Integer id = member.getId();
        String mobile = member.getMobile();

        synchronized (Lock.REGISTER_MOBILE_USERNAME) {
            findById = memberDaoImpl.findById(id);
            if (StringUtil.isNotBlankObject(mobile)) {
                if (!mobile.equals(findById.getMobile())) {
                    Set<String> findKeyByUserId = roleDaoImpl.findKeyByUserId(id);
                    Member findByMobile = memberDaoImpl.findByRoleMobile(findKeyByUserId, mobile);
                    if (StringUtil.isNotBlankObject(findByMobile) && findByMobile.getId().intValue() != id) {
                        throw new TransException("手机号已存在！");
                    }
                }
            }

            updatePartialById = memberDaoImpl.updatePartialById(member);
        }

        if (updatePartialById > 0) {
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.HEAD_IMG, member.getHeadImg(),
                findById.getHeadImg());
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.ID_CARD_FRONT,
                member.getIdCardFront(), findById.getIdCardFront());
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.ID_CARD_VERSO,
                member.getIdCardVerso(), findById.getIdCardVerso());
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.LABOR_CARD,
                member.getLaborCard(), findById.getLaborCard());
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.FOOD_CARD, member.getFoodCard(),
                findById.getFoodCard());
            FileDepotUtil.updateSync(EFileTable.MEMBER.getCode(), ConstantFileFieldName.TELECOM_CARD,
                member.getTelecomCard(), findById.getTelecomCard());
        }
        return updatePartialById;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容相同)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updateStaticPartialByIdList(Member member) {
        int updateStaticPartialByIdList = memberDaoImpl.updateStaticPartialByIdList(member);
        return updateStaticPartialByIdList;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容不相同)
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public int updateChangePartialByIdList(Member member) {
        int updateChangePartialByIdList = memberDaoImpl.updateChangePartialByIdList(member.getMembers());
        return updateChangePartialByIdList;
    }

    /**
     * 通过id查询
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public Member findById(Integer id) {
        Member findById = memberDaoImpl.findById(id);
        return findById;
    }

    /**
     * 通过id列表查询
     * 
     * @param ids
     * @return
     * @throws SQLException
     */
    @Override
    public ArrayList<Member> findByIdList(ArrayList<Integer> ids) {
        ArrayList<Member> findByIdList = memberDaoImpl.findByIdList(ids);
        return findByIdList;
    }

    /**
     * 通过对象查询id列表
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public ArrayList<Integer> findIdByDto(Member member) {
        ArrayList<Integer> findIdByDto = memberDaoImpl.findIdByDto(member);
        return findIdByDto;
    }

    /**
     * 清空数据(物理清空)
     * 
     * @throws SQLException
     */
    @Override
    public void clear() {
        memberDaoImpl.clear();
    }

    /**
     * 通过手机号查询
     * 
     * @param mobile
     * @return
     */
    @Override
    public Member findByMobile(String mobile) {
        return memberDaoImpl.findByMobile(mobile);
    }

    /**
     * 通过手机号查询
     * 
     * @param roles     角色列表
     * @param mobile    
     * @return
     */
    @Override
    public Member findByRoleMobile(Set<String> roles, String mobile) {
        return memberDaoImpl.findByRoleMobile(roles, mobile);
    }

    /**
     * 通过id更新手机号
     * 
     * @param token
     * @return
     * @throws IOException 
     */
    @Override
    public int updateMobileById(TokenVo token) throws IOException {
        int updatePartialById = 0;
        Member member = token.getMember();
        Integer id = member.getId();
        String mobile = member.getMobile();
        String string = new StringBuilder(TokenUtil.getTokenId()).append(VerifyCodeUtil.SMS)
            .append(token.getVerifyCodePrefix()).toString();
        Verify verifyCode = VerifyCodeUtil.getVerifyCode(string);

        if (!VerifyCodeUtil.verifyAndClearCode(verifyCode, token.getVerifyCodeValue())) {
            throw new TransException(TransErrorCode.ERR_CODES.getMsg());
        }

        Member findById = memberDaoImpl.findById(id);
        if (StringUtil.isBlankObject(findById)) {
            throw new TransException("用户不存在！");
        }
        String m = findById.getMobile();
        if (StringUtil.isNotBlankObject(m) && !m.equals(verifyCode.getUsername())) {
            throw new TransException("验证码不是旧手机的！");
        }

        synchronized (Lock.REGISTER_MOBILE_USERNAME) {
            Set<String> findKeyByUserId = roleDaoImpl.findKeyByUserId(id);
            Member findByMobile = memberDaoImpl.findByRoleMobile(findKeyByUserId, mobile);
            if (StringUtil.isNotBlankObject(findByMobile) && findByMobile.getId().intValue() != id) {
                throw new TransException("手机号已存在！");
            }

            Member mem = new Member();
            mem.setId(id);
            mem.setMobile(mobile);
            mem.updateInit();
            updatePartialById = memberDaoImpl.updatePartialById(mem);
        }
        return updatePartialById;
    }

    /**
     * 通过id验证旧密码修改密码
     * 
     * @param member
     * @return
     * @throws Exception 
     */
    @Override
    public int updatePwdByOldPwd(AuthcUser member) throws Exception {
        Integer id = member.getId();
        Member findById = memberDaoImpl.findById(id);
        // 查看旧密码是否输入正确
        // 判断密码是否正确
        if (!PwdUtil.matchesPwd(member.getOldPwd(), findById.getPwd())) {
            throw new TransException(TransErrorCode.ERR_OLD_PWD);
        }

        Member mem = new Member();
        mem.updateInit();
        mem.setId(id);
        mem.setPwd(PwdUtil.encryptionPwd(member.getPwd()));
        return memberDaoImpl.updatePartialById(mem);
    }

    /**
     * 通过id验证短信修改密码
     * 
     * @param token
     * @return
     * @throws Exception 
     */
    @Override
    public int updatePwdBySms(Token token) throws Exception {
        Member mem = new Member();
        mem.updateInit();
        mem.setId(token.getMember().getId());
        mem.setPwd(PwdUtil.encryptionPwd(token.getMember().getPwd()));
        return memberDaoImpl.updatePartialById(mem);
    }

    /**
     * 通过id修改状态
     * 
     * @param member
     * @return
     * @throws IOException 
     */
    @Override
    public int updateStatusById(Member member) throws IOException {
        Integer id = member.getId();
        Integer status = member.getStatus();

        Member mem = new Member();
        mem.updateInit();
        mem.setId(id);
        mem.setStatus(status);
        int updatePartialById = memberDaoImpl.updatePartialById(mem);

        // 如果禁用就踢出此账号的所有Token
        if (status == EUserStatus.DISABLE.getCode()) {
            Member findById = memberDaoImpl.findById(id);
            if (StringUtil.isNotBlankObject(findById)) {
                TokenUtil.logout(findById.getNo());
            }
        }
        return updatePartialById;
    }

    /**
     * 通过帐号查询
     * 
     * @param username
     * @return
     */
    @Override
    public Member findByUsername(String username) {
        return memberDaoImpl.findByUsername(username);
    }

    /**
     * 通过角色和帐号查询
     * 
     * @param roles     角色列表
     * @param username  帐号
     * @return
     */
    @Override
    public Member findByRoleUsername(Set<String> roles, String username) {
        return memberDaoImpl.findByRoleUsername(roles, username);
    }

    /**
     * 通过微信唯一标识查询
     * 
     * @param wxUnionid
     * @return
     */
    @Override
    public Member findByWxUnionid(String wxUnionid) {
        return memberDaoImpl.findByWxUnionid(wxUnionid);
    }

    /**
     * 通过微信唯一标识查询
     * 
     * @param roles     角色列表
     * @param wxUnionid 微信唯一编号
     * @return
     */
    @Override
    public Member findByRoleWxUnionid(Set<String> roles, String wxUnionid) {
        return memberDaoImpl.findByRoleWxUnionid(roles, wxUnionid);
    }

    /**
     * 通过微信openid查询
     * 
     * @param roles     角色列表
     * @param openid
     * @return
     */
    @Override
    public Member findByRoleOpenid(Set<String> roles, String openid) {
        return memberDaoImpl.findByRoleOpenid(roles, openid);
    }

    /**
     * 修改支付密码
     * 
     * @param mem
     * @return
     */
    @Override
    public int updatePayPwd(AuthcUser mem) {
        Member findById = memberDaoImpl.findById(mem.getId());
        if (StringUtil.isBlankObject(findById)) {
            throw new TransException("用户不存在！");
        }
        int code = EGeneralYesNo.YES.getCode();
        if (EGeneralYesNo.YES.getCode() == findById.getIsPayPwd()) {
            if (!PwdUtil.matchesPwd(mem.getOldPayPwd(), findById.getPayPwd())) {
                throw new TransException("旧支付密码错误！");
            }
        } else {
            mem.setIsPayPwd(code);
        }
        return memberDaoImpl.updatePartialById(mem);
    }

    /**
     * 获取当前佣金信息
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public Member findBalance(Integer id) {
        return memberDaoImpl.findBalance(id);
    }

    /**
     * 获取当前余额信息
     * 
     * @param id
     * @return
     */
    @Override
    public Member findBrokerage(Integer id) {
        return memberDaoImpl.findBrokerage(id);
    }

    /**
     * 获取下级用户列表
     * 
     * @param member
     * @return
     */
    @Override
    public List<Member> findUnderlingByDto(Member member) {
        return memberDaoImpl.findUnderlingByDto(member);
    }

    /**
     * 通过编号查询
     * 
     * @param no
     * @return
     */
    @Override
    public Member findByNo(String no) {
        return memberDaoImpl.findByNo(no);
    }

    /**
     * 获取简历
     * 
     * @param id
     * @return
     */
    @Override
    public MemberVo findResume(Integer id) {
        return memberDaoImpl.findResume(id);
    }

    /**
     * 获取简历
     * 
     * @param member
     * @return
     */
    @Override
    public List<MemberVo> findResumeList(Member member) {
        return memberDaoImpl.findResumeList(member);
    }

    /**
     * 获取用户的当前诚意金信息
     * 
     * @param userId
     * @return
     */
    @Override
    public MemberVo findDeposit(Integer userId) {
        return memberDaoImpl.findDeposit(userId);
    }

    /**
     * 根据对象查询
     * 
     * @param member
     * @return
     * @throws SQLException
     */
    @Override
    public List<MemberVo> list(Member member) {
        return memberDaoImpl.list(member);
    }

    /**
     * 根据ID查询
     * 
     * @param id
     * @return
     * @throws SQLException
     */
    @Override
    public MemberVo getInfo(Integer id) {
        return memberDaoImpl.getInfo(id);
    }

    /**
     * 将佣金转入余额
     * 
     * @param balanceLog
     * @return
     * @throws IOException 
     */
    @Override
    public int balanceToBrokerage(BigDecimal total) throws IOException {
        int balanceToBrokerageGo = 0;
        Integer userId = TokenUtil.getUserId();
        synchronized (Lock.BALANCE_LOG) {
            balanceToBrokerageGo = memberServiceImpl.balanceToBrokerageGo(total, userId);
        }
        return balanceToBrokerageGo;
    }

    @Transactional
    public int balanceToBrokerageGo(BigDecimal total, Integer userId) throws IOException {
        Member findById = memberDaoImpl.findById(userId);
        BigDecimal balance = findById.getBalance();
        if (balance.doubleValue() < total.doubleValue()) {
            throw new TransException("佣金余额不足！");
        }

        // 修改
        Member member = new Member();
        member.updateInit();
        member.setId(userId);
        member.setBalance(balance.subtract(total));
        member.setBalanceWithdrawBrokerage(findById.getBalanceWithdrawBrokerage().add(total));
        member.setBrokerage(findById.getBrokerage().add(total));
        member.setBrokerageSum(findById.getBrokerageSum().add(total));
        int updatePartialById = memberDaoImpl.updatePartialById(member);
        if (updatePartialById < 1) {
            throw new TransException("修改用户余额失败！");
        }

        BalanceLog balanceLog = new BalanceLog();
        balanceLog.insertInit("佣金提现至余额", userId, total, balance, EBalanceType.WITHDRAW_BROKERAGE.getCode(), null,
            EBalanceTotalType.COMMISSION.getCode(), EBalanceCount.REDUCE.getCode(), null, null);
        int insert = balanceLogService.insert(balanceLog);
        if (insert < 1) {
            throw new TransException("佣金记录添加失败！");
        }
        balanceLog = new BalanceLog();
        balanceLog.insertInit("余额到账,佣金提现至余额", userId, total, findById.getBrokerage(),
            EBalanceType.WITHDRAW_BROKERAGE.getCode(), null, EBalanceTotalType.BALANCE.getCode(),
            EBalanceCount.ADD.getCode(), null, null);
        insert = balanceLogService.insert(balanceLog);
        if (insert < 1) {
            throw new TransException("余额记录添加失败！");
        }

        return updatePartialById;
    }

    /**
     * 通过订单ID查询
     * 
     * @return
     */
    @Override
    public Member findMerchantByOrderId(Integer goodsId) {
        return memberDaoImpl.findMerchantByOrderId(goodsId);
    }

    /**
     * 获取对应角色的用户列表
     * 
     * @param member
     * @return
     */
    @Override
    public List<MemberVo> listByRole(MemberVo member) {
        return memberDaoImpl.listByRole(member);
    }

    /**
     * 根据对象查询
     * 
     * @param member
     * @return
     */
    @Override
    public List<MemberVo> listUser(MemberVo member) {
        return memberDaoImpl.listUser(member);
    }

    @Override
    public BaseUser findByUserNo(String userNo) {
        return memberDaoImpl.findByNo(userNo);
    }

    /**
     * 获取下拉列表
     * 
     * @param member
     * @return
     */
    @Override
    public List<Select> select(MemberVo member) {
        return memberDaoImpl.select(member);
    }

    /**
     * 获取商家下拉列表
     * 
     * @param member
     * @return
     */
    @Override
    public List<Select> selectMerchant(MemberVo member) {
        return memberDaoImpl.selectMerchant(member);
    }

    /**
     * 用户续租
     * 
     * @param member
     * @return
     * @throws IOException 
     */
    @Override
    public int addDayGoOn(MemberVo mem) {
        synchronized (Lock.ADD_DAY_GO_ON) {
            Member findByNo = memberDaoImpl.findByNo(mem.getNo());
            if (StringUtil.isBlankObject(findByNo)) {
                throw new TransException("用户不存在！");
            }
            if (findByNo.getDisableAtType() != EDisableAtType.TIME_LIMIT.getCode()) {
                throw new TransException("用户有效类型不是限时！");
            }

            long time = findByNo.getDisableAt().getTime();
            long nowLong = DateUtil.nowLong();
            if (time < nowLong) {
                time = nowLong;
            }
            mem.setDisableAt(new Date(time + Constant.MILLIS_DAY * mem.getDayGoOn()));
            return memberDaoImpl.updatePartialByNo(mem);
        }
    }

    /**
     * 审核认证信息
     * 
     * @param member
     * @return
     */
    @Override
    public int auditAuth(Member mem) {
        return memberDaoImpl.updatePartialById(mem);
    }

}